/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.posplus.losspreventiondataimporter.importer;

import com.posplus.lossprevention.APDAOFactory;
import com.posplus.lossprevention.mapping.Actions;
import com.posplus.lossprevention.mapping.Cashiers;
import com.posplus.lossprevention.mapping.Departments;
import com.posplus.lossprevention.mapping.Items;
import com.posplus.lossprevention.mapping.NoSales;
import com.posplus.lossprevention.mapping.Products;
import com.posplus.lossprevention.mapping.Registers;
import com.posplus.lossprevention.mapping.Stores;
import com.posplus.lossprevention.mapping.TransactionDetails;
import com.posplus.lossprevention.mapping.Transactions;
import com.posplus.lossprevention.mapping.UniqueTransaction;
import com.posplus.strack.mapping.RegisterTrans;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.posplus.losspreventiondataimporter.service.ActionsService;
import com.posplus.losspreventiondataimporter.service.CashiersService;
import com.posplus.losspreventiondataimporter.service.DepartmentsService;
import com.posplus.losspreventiondataimporter.service.ItemsService;
import com.posplus.losspreventiondataimporter.service.NoSalesService;
import com.posplus.losspreventiondataimporter.service.ProductsService;
import com.posplus.losspreventiondataimporter.service.RegisterTransService;
import com.posplus.losspreventiondataimporter.service.RegistersService;
import com.posplus.losspreventiondataimporter.service.StoresService;
import com.posplus.losspreventiondataimporter.service.TransactionDetailsService;
import com.posplus.losspreventiondataimporter.util.ListToMap;
import org.apache.log4j.Logger;

/**
 *
 * @author scottw
 */
public class RegisterTransImporter {

    private APDAOFactory lpFactory;
    private RegisterTransService regTransService;
    private String storeCode;

    public RegisterTransImporter(RegisterTransService regTransService,
	    APDAOFactory lpFactory) {

	this.lpFactory = lpFactory;
	this.regTransService = regTransService;
    }

    public void dataImport(Calendar start, Calendar end) {
	List<RegisterTrans> regTrans = regTransService.getBetweenDates(start, end);

	mapAndPersist(regTrans, lpFactory);
    }

    private void mapAndPersist(List<RegisterTrans> registerTrans, APDAOFactory lpFactory) {
	StoresService storeService = new StoresService(lpFactory);
	Map<String, Stores> stores = ListToMap.storesToMap(storeService.getAll());
	DepartmentsService departmentsService = new DepartmentsService(lpFactory);
	Map<Integer, Departments> departments = ListToMap.departmentsToMap(departmentsService.getAll());
	ProductsService productsService = new ProductsService(lpFactory);
	Map<String, Products> products = ListToMap.productsToMap(productsService.getAll());
	ActionsService actionsService = new ActionsService(lpFactory);
	Map<String, Actions> actions = ListToMap.actionsToMap(actionsService.getAll());

	List<NoSales> noSales = new ArrayList<NoSales>();
	List<TransactionDetails> transactionDetails = new ArrayList<TransactionDetails>();
	List<Items> items = new ArrayList<Items>();


	try {
	    Stores store = stores.get(storeCode);
	    if (store == null) {
		throw new RuntimeException("Store " + storeCode + " not found.");
	    }

	    Map<Integer, Registers> registers = ListToMap.registersToMap(store.getRegisterses());
	    Map<String, Cashiers> cashiers = ListToMap.cashiersToMap(store.getCashierses());
	    Map<UniqueTransaction, Transactions> transactions = ListToMap.transactionsToMap(store.getTransactionses());

	    Iterator<RegisterTrans> iter = registerTrans.iterator();
	    while (iter.hasNext()) {
		RegisterTrans next = iter.next();

		try {
		    Registers register = registers.get(next.getId().getRegisterNo().intValue());
		    if (register == null) {
			Logger.getRootLogger().debug("Register " + next.getId().getRegisterNo() + " not found");
			register = new Registers(store, next.getId().getRegisterNo());
			Logger.getRootLogger().debug("Creating new Register: " + register);
			RegistersService registerService = new RegistersService(lpFactory);
			registerService.save(register);
			registers.put(register.getNumber(), register);
		    }

		    Cashiers cashier = cashiers.get(next.getId().getEmpNo().toString());
		    if (cashier == null) {
			Logger.getRootLogger().debug("Cashier " + next.getId().getEmpNo() + " not found");
			cashier = new Cashiers(store, next.getId().getEmpNo().toString(), "AUTOFILL", "AUTOFILL", "AUTOFILL", null, null, null);
			Logger.getRootLogger().debug("Creating new Cashier: " + cashier);
			CashiersService cashierService = new CashiersService(lpFactory);
			cashierService.save(cashier);
			cashiers.put(cashier.getCode(), cashier);
		    }

		    if ("ns".equalsIgnoreCase(next.getTransSubtype())) {
			NoSales noSale = new NoSales(register, cashier, next.getDatetime());
			noSales.add(noSale);
		    } else {
			UniqueTransaction uniqueTrans = new UniqueTransaction(next.getProcDate().getTime(), store.getCode(), cashier.getCode(), register.getNumber(), next.getId().getTransNo());
			Transactions transaction = transactions.get(uniqueTrans);
			if (transaction == null) {
 			    throw new RuntimeException("Transaction " + next.getId() + " not found.");
			}

			Departments department = departments.get(next.getDepartment().intValue());
			if (department == null) {
			    department = new Departments(next.getDepartment().intValue(), 0, "AUTOFILL", null, null);
			    departmentsService.save(department);
			    departments.put(department.getNumber(), department);
			}
			Products product = products.get(next.getUpc());
			if (product == null) {
			    product = new Products(department, next.getUpc(), "AUTOFILL", null);
			    productsService.save(product);
			    products.put(product.getUpc(), product);
			}
			Actions action = actions.get(getActionCode(next));
			if (action != null) {
			    TransactionDetails transDetail = new TransactionDetails(transaction, department, action, next.getId().getLineNo(), null);
			    transactionDetails.add(transDetail);

			    if (requiresItem(next)) {
				Items item = new Items(product, transDetail, next.getQuantity().floatValue(), next.getTotal());
				items.add(item);
			    }
			}
		    }
		} catch (RuntimeException ex) {
		    Logger.getLogger(RegisterTransImporter.class).warn(ex);
		}
	    }
	} catch (RuntimeException ex) {
	    Logger.getLogger(RegisterTransImporter.class).warn(ex);
	}

	if (noSales.size() > 0) {
	    NoSalesService nsService = new NoSalesService(lpFactory);
	    //nsService.bulkInsert(noSales);
	    nsService.saveAll(noSales);
	}

	if (transactionDetails.size() > 0) {
	    TransactionDetailsService tdService = new TransactionDetailsService(lpFactory);
	    //tdService.bulkInsert(transactionDetails);
	    tdService.saveAll(transactionDetails);
	}

	if (items.size() > 0) {
	    ItemsService itemService = new ItemsService(lpFactory);
	    //itemService.bulkInsert(items);
	    itemService.saveAll(items);
	}
    }

    private static boolean isStoreCoupon(int attributes) {
	int storeCouponMask = 64;

	return (attributes & storeCouponMask) == storeCouponMask;
    }

    private static boolean isScanned(int attributes) {
	int scannedMask = 65536;

	return (attributes & scannedMask) == scannedMask;
    }

    private static boolean isVoid(int attributes) {
	int voidMask = 2097152;

	return (attributes & voidMask) == voidMask;
    }

    private static boolean isRefund(int attributes) {
	int refundMask = 4194304;

	return (attributes & refundMask) == refundMask;
    }

    private static String getActionCode(RegisterTrans registerTrans) {
	if (!isScanned(registerTrans.getAttributes())) {
	    return "NSC";
	} else if (isRefund(registerTrans.getAttributes())) {
	    return "RF";
	} else if (isStoreCoupon(registerTrans.getAttributes())) {
	    return "SC";
	} else if (isVoid(registerTrans.getAttributes())) {
	    return "VD";
	} else if ("I".equalsIgnoreCase(registerTrans.getTransType())) {
	    return "I";
	} else if ("T".equalsIgnoreCase(registerTrans.getTransType())) {
	    return "T";
	} else {
	    return "Not going to be found.";
	}
    }

    private static boolean requiresItem(RegisterTrans registerTrans) {
	if ("T".equalsIgnoreCase(registerTrans.getTransType()) || "Z".equalsIgnoreCase(registerTrans.getTransType())) {
	    return false;
	}

	return true;
    }

    public String getStoreCode() {
	return storeCode;
    }

    public void setStoreCode(String storeCode) {
	this.storeCode = storeCode;
    }
}
